feat(primitives): add Rx compatibility APIs and advanced sinks#63
Merged
Conversation
API surface: - Add Rx-compatible Signal aliases for Return, Empty, Never, Throw, Timer, Merge, and Switch. - Add async Create/Defer overloads, indexed Select/MapIndexed, Task ToObservable/ToSignal, task Concat/Chain, scheduler-aware ToObservable, and object Synchronize/SynchronizeObject support. - Update public API baselines for ReactiveUI.Primitives and ReactiveUI.Primitives.Reactive. Build and test fixes: - Fix generate-publicapi.ps1 path construction under Windows PowerShell. - Disambiguate tests after the new overloads. - Disable the WindowsAppSDK Undocked RegFree WinRT auto-initializer for WinUI tests to avoid compiling package source that violates CA5392 while preserving self-contained dispatcher tests.
Operators: - add Rx-name aliases for Publish, Replay, RefCount, SubscribeSafe, StartWith, Buffer, Finally, Throttle, Catch, SelectMany, and Merge - add bounded enumerable Blend/Merge support so migrated DynamicData pipelines can avoid local ReactiveCompatibility operators - add cleanup argument validation for Finally/OnCleanup parity Public API: - regenerate ReactiveUI.Primitives and ReactiveUI.Primitives.Reactive shipped API baselines for all target frameworks Tests: - add TUnit coverage for DynamicData migration aliases, SubscribeSafe failure handling, bounded Merge, Buffer, Throttle, and Finally Validation: - built ReactiveUI.Primitives, ReactiveUI.Primitives.Reactive, DynamicData, DynamicData.Reactive, and the solution - ran ReactiveUI.Primitives.Tests net10.0 executable: 391/391 passed
Update StyleSharp.Analyzers package version from 3.11.1 to 3.11.2 in src/Directory.Packages.props to pick up the patch release.
Review comments: - address generic catch review threads by filtering fatal runtime exceptions before converting ordinary delegate/enumerator failures to OnError Implementation: - add a shared FatalExceptionHelper used by Connectable Publish, bounded Blend/Merge, MapIndexed, SubscribeSafe, and enumerable SelectMany Validation: - dotnet build ReactiveUI.Primitives net8.0 - dotnet build ReactiveUI.Primitives.Reactive net8.0 - dotnet build ReactiveUI.Primitives.Tests net10.0 - ReactiveUI.Primitives.Tests net10.0 executable: 391/391 passed
CI: - add Android-generated Resource type baselines for ReactiveUI.Primitives and ReactiveUI.Primitives.Reactive on net10.0-android and net11.0-android Validation: - dotnet build ReactiveUI.Primitives net10.0-android Release - dotnet build ReactiveUI.Primitives.Reactive net10.0-android Release - net11.0-android local validation is blocked by missing Android API level 37 on this machine; CI has the required SDK
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #63 +/- ##
==========================================
+ Coverage 93.36% 93.85% +0.49%
==========================================
Files 462 480 +18
Lines 17208 17736 +528
Branches 2052 2101 +49
==========================================
+ Hits 16067 16647 +580
+ Misses 898 856 -42
+ Partials 243 233 -10 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Review coverage: - add focused TUnit coverage for Rx factory aliases, connectable aliases, SubscribeSafe, bounded Merge, SelectMany enumerable branches, event-pattern delegate variants, and Optional null semantics - raise local patch coverage for coverable runtime additions to 98.54% Runtime fixes: - keep async Signal.Create subscription cancellation lifetime valid after async setup completes - move Signal<T> dispatch helper into the static helper section to satisfy SST1204 without suppression API and build support: - ship Range, Interval, and Concat Rx alias API baselines for Primitives and Primitives.Reactive - add netfx AllowNullAttribute polyfill support for the updated Optional API
## Reactive operators - Preserve Rx SelectMany concurrent flattening semantics by delegating through Map(...).Merge(). - Add coverage for concurrent inner emissions used by DynamicData-style Rx migration code. ## Connectable signals - Replace disposable-field suppressions with an actual IDisposable implementation on ConnectableSignal<T>. - Latch terminal/disposed state to prevent reconnecting completed or disposed connectable sources. - Add public API baseline entries and focused TUnit coverage for disposal and RefCount reconnection behavior. ## Test stability - Make the async throttle supersession test deterministic with a manual TimeProvider instead of wall-clock timing.
## What changed - Increase the default timeout used by string-pattern Filter regex construction from one second to thirty seconds. - Preserve explicit Regex overload behavior so caller-supplied timeout settings and error forwarding are unchanged. ## Validation - Built ReactiveUI.Primitives.Extensions.Tests for net10.0 and net9.0 Release. - Ran the net10.0 and net9.0 Release Microsoft Testing Platform executables. - Ran net10.0 Release MTP coverage for extension tests and inspected the changed shared extension file with the MTP coverage MCP. - Built ReactiveUI.Primitives.slnx locally.
Remove the accidental public ConnectableSignal<T>.Dispose() API from the DynamicData compatibility branch while preserving the terminal latch used by Publish().RefCount(). Update Core public API baselines and remove the test that asserted the rejected public dispose surface. The connection lifetime remains owned by Connect() callers. Validated with ReactiveUI.Primitives.Tests net8.0, ReactiveUI.Primitives.Reactive net8.0, and the TUnit test executable.
## What changed - Remove the CA1001/S2931 suppression attributes from ConnectableSignal<T>. - Keep Connect() caller-owned lifetime semantics by storing the active connection in a non-disposable StrongBox slot while the returned Connection handle owns disposal. - Preserve the terminal latch behavior added for Publish().RefCount(). ## Validation - Built ReactiveUI.Primitives.Core for net10.0. - Built and ran ReactiveUI.Primitives.Tests net10.0 with Microsoft Testing Platform/TUnit. - Built ReactiveUI.Primitives.slnx locally with Android and Apple target framework exclusions.
GitHub only registered the standalone CodeQL check for the previous PR head. This no-op commit forces a fresh pull_request synchronize event so Build, SonarCloud, and CodeQL all attach to the current branch head.
## What changed - Update README package guidance for the current ReactiveUI.Primitives package set, including reactive UI package variants. - Document multi-source SyncLatest/CombineLatest, Rx-name SelectMany compatibility, and Filter regex timeout behavior. - Expand README migration guidance for an existing lean xyz project and a new xyz.Reactive package using ReactiveUI.Primitives.Reactive packages. - Update packaged Skill.md frontmatter, package chooser, API landmarks, framework notes, and Rx migration playbook. ## Validation - Ran git diff --check. - Packed ReactiveUI.Primitives with dotnet pack --no-build and verified README.md, Skill.md, and .agents/skills/reactiveui-primitives/SKILL.md are present in the nupkg.
Replace the task Chain/Concat implementation that composed ChainSignal over sources.Map(Signal.FromTask) with a dedicated TaskChainSignal/TaskChainCoordinator path. This removes the extra extension-method hop called out in PR review while preserving sequential task result ordering, source errors, task faults, null-task failures, and disposal behavior. Validation: dotnet build tests/ReactiveUI.Primitives.Tests -c Debug -f net10.0; ReactiveUI.Primitives.Tests.exe --results-directory TestResultsScratch/TaskChainDirect2 --output Normal; ReactiveUI.Primitives.Tests.exe --results-directory TestResultsScratch/TaskChainDirectCoverage2 --output Normal --coverage; dotnet build ReactiveUI.Primitives.slnx -c Debug -p:AndroidPrimitivesTargetFrameworks= -p:ApplePrimitivesTargetFrameworks=
- Move branch-added operator signals and sinks out of private nested types. - Add public API baselines for primitive and reactive Advanced namespaces.
- Move the async create subscription lifetime helper into Advanced. - Add public API baselines for primitive and reactive packages.
- Add focused tests for async lifetimes, connectable signals, create overloads, fatal exceptions, and advanced coordinators. - Extract small internal helpers for shared observer lifetimes and hard-to-reach coordinator guards.
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
|
glennawatson
approved these changes
Jun 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What kind of change does this PR introduce?
What is the new behavior?
What is the current behavior?
What might this PR break?
Checklist
mainbranchAdditional information
dotnet build "ReactiveUI.Primitives.slnx" -c Release -v:minimaldotnet test "ReactiveUI.Primitives.slnx" -c Release --no-build